#include <Windows.h>
#include <d3dx9.h>
#include "Exception.h"
#include "Amazon.h"
#include "resource.h"
#include "Player.h"
#include "ScanFile.h"
#include "ViewList.h"
#include "Config.h"
#include "Backup.h"
#include <fstream>
#include <gdiplus.h>
#include "XPlan.h"
#include "XText.h"
using namespace Gdiplus;

using namespace std;

LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
Image *_image = NULL;
ScanFile _scanFile;
ViewList *_pViewList = NULL;
Config _config;
Backup _backup;
XPlan g_plan;
XText g_text;
RECT g_rect = {0,0,0,0};
File *g_pCurFile = NULL;
std::wstring g_xtext;

LRESULT CALLBACK MainProc(HWND Dlg,UINT message,WPARAM wParam,LPARAM lParam);

/**
Main Initialisation
*/
void init()
{
	try
	{
	::CoInitialize(NULL);
	ULONG_PTR           gdiplusToken;
	GdiplusStartupInput gdiplusStartupInput;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
		
	_scanFile.scan( _config.get( L"path" ), L"*.*" );	
	g_pCurFile =_scanFile.getCurFile();
	g_xtext = g_pCurFile->getTag("ARTIST") + L" - " + g_pCurFile->getTag("TITLE");
	g_pCurFile->play();
	//_scanFile.play();

	/*
	_backup.init( _config.get( L"database" ) );	
	std::map<std::string,Item> map;
	if ( !g_pCurFile->getTag("ARTIST").empty() )
	{
		map["TITLE"] = g_pCurFile->getTagA("TITLE");
		map["ALBUM"] = g_pCurFile->getTagA("ALBUM");
		map["ARTIST"] = g_pCurFile->getTagA("ARTIST");
		map["TRACK"] = wstringTostring(g_pCurFile->getName());
		_backup.add( map );
	}
	*/

	} catch ( Exception &ex )
	{
		::MessageBox( NULL, ex.getWhat().c_str(), L"Error", MB_ICONERROR );
	}
}


/**
Direct3D Initialisation
@param[in]	hWnd	window's handle
*/
HRESULT InitD3D( HWND hWnd )
{
	// Create the D3D object.
	if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return E_FAIL;

	// Set up the structure used to create the D3DDevice. Since we are now
	// using more complex geometry, we will create a device with a zbuffer.
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof(d3dpp) );
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;


	// Create the D3DDevice
	if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp, &g_pd3dDevice ) ) )
	{
		return E_FAIL;
	}

	// Turn off culling
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	// Turn off D3D lighting
	g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

	// Turn on the zbuffer
	g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

	
	g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
	g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA);
	g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB(0xFF,50,50) );
	


	return S_OK;
}

/**
Init plan, Texture and Text
*/
HRESULT InitGeometry()
{
	for (int i=0;i<5;i++)
		g_plan.add(L"out.jpg");

	g_plan.create(g_pd3dDevice);

	g_text.create(g_pd3dDevice);

	return S_OK;
}

/**
Cleanup D3Dobject
*/
VOID Cleanup()
{
	if( g_pd3dDevice != NULL )
		g_pd3dDevice->Release();
	if( g_pD3D != NULL )
		g_pD3D->Release();
}

/**
Setup Matrices in 3D World
*/
VOID SetupMatrices()
{
	// Set up world matrix
	D3DXMATRIXA16 matWorld;
	D3DXMatrixIdentity( &matWorld );
	//D3DXMatrixRotationX( &matWorld, timeGetTime()/1000.0f );
	//D3DXMatrixTranslation( &matWorld, 0.0f, 1.0f, 0.0f );
	g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );


	D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-7.0f );
	D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
	D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
	D3DXMATRIXA16 matView;
	D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
	g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
	g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

/**
Looped D3D render function
*/
VOID Render()
{
	// Clear the backbuffer and the zbuffer
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
		D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

	// Begin the scene
	if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
	{
		// Setup the world, view, and projection matrices
		SetupMatrices();
		//g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
		//g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
  g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
		g_plan.draw(g_pd3dDevice);
		g_rect.top = g_rect.bottom / 1.2;
		g_text.draw( &g_rect, g_xtext.c_str(), 0x90FFFFFF );
		// End the scene
		g_pd3dDevice->EndScene();
	}

	// Present the backbuffer contents to the display
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

/**
Entry point WinMain entrie
*/
int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR     lpCmdLine,
					 int       nCmdShow)
{
	WNDCLASSEX principale;
	principale.cbSize=sizeof(WNDCLASSEX);
	principale.style=CS_HREDRAW|CS_VREDRAW;
	principale.lpfnWndProc=MainProc;
	principale.cbClsExtra=0;
	principale.cbWndExtra=0;
	principale.hInstance=hInstance;
	principale.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	principale.hCursor=LoadCursor(NULL,IDC_ARROW);
	principale.hbrBackground=reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
	principale.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
	principale.lpszClassName = TEXT("std");
	principale.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
	RegisterClassEx(&principale);

	HWND hWnd;
	hWnd=CreateWindowEx(
		WS_EX_CLIENTEDGE,
		TEXT("std"),
		TEXT("Visual MP3"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
		);

	init();

	assert( InitD3D( hWnd ) == S_OK );

	assert( InitGeometry() == S_OK );
	
	ShowWindow(hWnd,SW_SHOW);
	MSG msg;
	ZeroMemory( &msg, sizeof(msg) );
	while( msg.message != WM_QUIT )
	{
		if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
			Render();
	}
	return 0;
}

/**
Paint la fenetre principal
*/
VOID OnPaint(HDC hdc)
{
	if ( _image == NULL )
		return ;
   Graphics graphics(hdc);
   Pen      pen(Color(255, 0, 0, 255));
   graphics.DrawImage( _image, 0, 0);
}

/**
OnCommand
*/
void  OnCommand(WPARAM wParam, LPARAM lParam)
{
	int cmd = LOWORD(wParam);
	switch( cmd )
	{
	case ID_FILE_OPEN :
		Player::getInstance()->load("LaFanFare.mp3");
		Player::getInstance()->play();
		break;
	}
}

/**
On Key down
@param[in]	key ascii key pressed
@return 0
*/
int keydown(char key)
{
	g_plan.move(L"empty.jpg");
	_scanFile.next();
	if ( !_scanFile.getCurFile()->getTag("ARTIST").empty() )
	{
		g_xtext = _scanFile.getCurFile()->getTag("ARTIST") 
			+ L" - " + _scanFile.getCurFile()->getTag("TITLE");
	} else {
		g_xtext = _scanFile.getCurFile()->getName();
	}
	switch(key)
	{
	case 'a':
		break;
	}
	return 0;
}

/**
MainProc
*/
LRESULT CALLBACK MainProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam)
{
	HDC hDC;
	PAINTSTRUCT paintst;
	switch (mes)
	{
	case WM_CREATE:
		_pViewList = new ViewList( hWnd, iSize(100,100) );
		::GetClientRect( hWnd, &g_rect );
		g_rect.left = 0;
		return 0;
	/*
	case WM_SIZE:
		return 0;*/
	case WM_DESTROY:
		Cleanup();
		PostQuitMessage(0);
		return 0;
	case WM_COMMAND:
		OnCommand( wParam, lParam );
	case WM_KEYDOWN:
		return keydown(wParam);
	default:
		return DefWindowProc(hWnd, mes, wParam, lParam);
	}
}